package com.polaris.live.ui.party.utils

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.viewModelScope
import androidx.viewpager2.widget.ViewPager2
import com.blankj.utilcode.util.StringUtils
import com.polaris.live.adapter.party.SpectatorFragmentAdapter
import com.polaris.live.common.constant.CommonConst
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.network.AppException
import com.polaris.live.common.network.parseState
import com.polaris.live.common.util.LogExt
import com.polaris.live.common.util.ReflexUtils
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.constant.LiveConst
import com.polaris.live.im.sfs.core.SmartFoxManager
import com.polaris.live.popup.party.JoinRoomJoinMemberPopup
import com.polaris.live.resp.back_resp.DisplayUserBean
import com.polaris.live.resp.back_resp.PartyRoomInfoResp
import com.polaris.live.resp.bean.ExitLiveBean
import com.polaris.live.translation.R.string
import com.polaris.live.ui.live.bean.LiveInitInfo
import com.polaris.live.ui.live.widget.PartyEditView
import com.polaris.live.ui.party.bean.PartySpectatorBean
import com.polaris.live.ui.party.bean.RoomState
import com.polaris.live.ui.party.listener.OnSpectatorFragmentListener
import com.polaris.live.ui.party.listener.PartyImListener
import com.polaris.live.ui.party.listener.RoomControlListener
import com.polaris.live.ui.party.utils.AutoGetRoomProxy.Companion.initPartySpectatorBean
import com.polaris.live.utils.route.RoutePath
import com.polaris.live.utils.route.Router
import com.polaris.live.viewmodel.party.PartySpectatorModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * 房间控制 自动拉取下一个数据   切换Im监听  控制登录
 *
 * @author Created by 天晴 on 2024/2/28 14:23
 * @since 1.0.0
 **/
class RoomControlProxy(
    @LiveConst.RequestType private val mRequestType: Int,   //请求类型
    private val mViewModel: PartySpectatorModel,
    private val mOwner: LifecycleOwner,
    private val mEditView: PartyEditView,
    private val mViewpage2: ViewPager2,
    private val mAdapter: SpectatorFragmentAdapter,
    private val mRoomControlListener: RoomControlListener,
    private val mOnSpectatorFragmentListener: OnSpectatorFragmentListener,
) {

    private var mCurrentBean: PartySpectatorBean? = null //当前界面数据
    private val mAutoGetRoomProxy by lazy {
        AutoGetRoomProxy(
            mRequestType,
            mEditView,
            mAdapter,
            mViewModel,
            mOwner,
            mOnSpectatorFragmentListener
        ) {
            mCurrentBean?.let {
                if (it.roomStateErrorCode == CommonConst.ErrorCode.LIVE_EMPTY) {
                    val bd = currentItemNext()
                    if (!bd) { //下个直播间为空，且当前直播间不存在 房间
                        mRoomControlListener.exitSuccess()
                    }
                }
            }
        }
    }

    /**
     * 禁止滑动
     */
    private var mProhibitSliding = true //加入了一次房间可以滑动

    /**
     * Im消息控制
     */
    private var mPartyImProxy: PartyImProxy? = null

    init {
        mViewpage2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageScrollStateChanged(state: Int) {
                when (state) {
                    ViewPager2.SCROLL_STATE_IDLE -> {
                        slidingSwitch()
                    }

                    ViewPager2.SCROLL_STATE_DRAGGING -> {
                    }

                    ViewPager2.SCROLL_STATE_SETTLING -> {
                    }
                }
            }
        })

        /**
         *加入直播间回调
         */
        mViewModel.joinLiveLiveData.observe(mOwner) { reusltState ->
            mCurrentBean?.fragment?.unloading()
            parseState(reusltState, { lli ->
                handlerSuccess(lli)
            }, {
                handlerError(it) {}
            })
        }
        /**
         * 重连
         */
        mViewModel.recoverJoinLiveData.observe(mOwner) { reusltState ->
            parseState(reusltState, { lli ->
            }) {
                handlerError(it) {
                    //直播im是连接的，但是重新加入直播间失败，延迟1秒重试
                    if (SmartFoxManager.isLiveConnected()) {
                        mCurrentBean?.let { data ->
                            mViewModel.recoverJoinLive(data.mAnchorId, data.password, 2000, data.roomId)
                        }
                    }
                }
                LogExt.logE("--live", "recoverJoin", it)
            }
        }
        /**
         * 退出直播间回调
         */
        mViewModel.exitLiveLiveData.observe(mOwner) {
            //不为空说明是切换直播间，开始加入新的直播间
            if (it.bean != null) {
                mRoomControlListener.exitLastSuccess()
                //相等才进入下个直播间不相等不进入
                if (mCurrentBean == it.bean) {
                    againEnterRoom(false)
                } else {
                    mCurrentBean?.fragment?.unloading()
                }
            } else {
                if (it.exitAndFinish) {
                    mRoomControlListener.exitSuccess()
                } else {
                    mCurrentBean?.fragment?.exitRoom()
                }

            }
        }
    }

    private fun handlerSuccess(lli: LiveInitInfo) {
        mRoomControlListener.joinSuccess(lli)
        LogExt.logE("--live", "joinLiveLiveData ------加入直播间回调$lli")
        mProhibitSliding = false
        mOnSpectatorFragmentListener.prohibitSliding(mProhibitSliding, false)

        mCurrentBean?.takeIf { lli.info.userId == mCurrentBean?.mAnchorId }?.apply {
            roomId = lli.info.roomId ?: "${lli.info.userId}"
            if (lli.info.type == this.liveType) { //房间类型正确
                roomState = RoomState.ENTERROOM
                initIm(fragment, lli.info.liveId, lli.info.userId)
                fragment.initLiveInfo(lli, this.password)
            } else {
                roomState = RoomState.PREPARE
                val errorMessage: String
                val navigateAction: (() -> Unit)
                var tipShowType = TipsShowType.ERROR_LIVE_OTHER
                when (lli.info.type) {
                    LiveConst.Type.LIVE_AND_MATCH, LiveConst.Type.ONLY_LIVE, LiveConst.Type.ONLY_MATCH -> {
                        tipShowType = TipsShowType.ERROR_LIVE_CLOSE
                        errorMessage = StringUtils.getString(string.room_end)
                        navigateAction = { }
                    }

                    LiveConst.Type.PARTY_LIVE -> {
                        errorMessage =
                            StringUtils.getString(string.ta_open_party_live)
                        navigateAction = {
                            Router.instance.setPath(RoutePath.PARTY_SPECTATOR_ACTIVITY)
                                .withInt(LiveConst.Params.LIVETYPE, LiveConst.Type.PARTY_LIVE)
                                .withLong(LiveConst.Params.ANCHORID, mAnchorId)
                                .navigation(mViewpage2.context)
                        }
                    }

                    LiveConst.Type.VIDEO_PARTY -> {
                        errorMessage =
                            StringUtils.getString(string.ta_open_party_video_live)
                        navigateAction = {
                            Router.instance.setPath(RoutePath.PARTY_SPECTATOR_ACTIVITY)
                                .withInt(LiveConst.Params.LIVETYPE, LiveConst.Type.VIDEO_PARTY)
                                .withLong(LiveConst.Params.ANCHORID, mAnchorId)
                                .navigation(mViewpage2.context)
                        }
                    }

                    LiveConst.Type.PARTY_GAME_LIVE -> {
                        errorMessage =
                            StringUtils.getString(string.ta_open_game_party_live)
                        navigateAction = {
                            Router.instance.setPath(RoutePath.PARTY_GAME_SPECTATOR_ACTIVITY)
                                .withLong(LiveConst.Params.ANCHORID, mAnchorId)
                                .navigation(mViewpage2.context)
                        }
                    }

                    else -> {
                        errorMessage =
                            StringUtils.getString(string.ta_open_game_party_live_no)
                        navigateAction = {
                            ToastGravity.showGravity(string.version_does_not_support)
                        }
                    }
                }
                fragment.tipsShowType(
                    tipShowType,
                    errorMessage,
                    navigateAction
                )
            }
        }
    }

    private fun handlerError(appException: AppException, back: () -> Unit) {
        mCurrentBean?.roomState = RoomState.ERROR
        mCurrentBean?.roomStateErrorCode = appException.errCode
        when (appException.errCode) {
            CommonConst.ErrorCode.LIVE_EMPTY -> { //直播间不存在
                mCurrentBean?.fragment?.tipsShowType(
                    TipsShowType.ERROR_LIVE_CLOSE,
                    StringUtils.getString(string.ta_close_live)
                )
                val nextPos = mViewpage2.currentItem + 1
                if (mAdapter.getDataByIndex(nextPos) != null) {
                    mViewpage2.currentItem = nextPos
                } else {
                    mCurrentBean?.let { user ->
                        mAutoGetRoomProxy.getNextRoom(user.mAnchorId)
                    }
                }
            }

            CommonConst.ErrorCode.PARTY_NEED_PASSWORD -> { //需要密码
                partyRoomLockPopup()
            }

            CommonConst.ErrorCode.PARTY_PASSWORD_ERROR -> { //密码错误
                partyRoomLockPopup(true)
            }

            CommonConst.ErrorCode.PARTY_SEAT_NO -> { //麦位被禁
            }

            CommonConst.ErrorCode.KICK_ROOM -> { //KICK_ROOM 被踢出了房间
                ToastGravity.showGravity(StringUtils.getString(string.kicked_out_room_tips))
                mRoomControlListener.exitSuccess()
            }

            CommonConst.ErrorCode.HAVE_MEMBER -> { //需要成员才能进入
                appException.ext?.get("room")?.let { room ->
                    val map = (room as? Map<String, Any>) ?: return@let
                    val bean = ReflexUtils.fromMap<PartyRoomInfoResp>(map) ?: return@let

                    JoinRoomJoinMemberPopup.show(
                        mViewpage2.context,
                        mViewModel,
                        bean,
                        { mRoomControlListener.exitSuccess() }
                    ) {
                        ToastGravity.showGravity(string.join_successfully)
                        againEnterRoom(true)
                    }
                }

            }

            else -> {
                mRoomControlListener.joinError(appException)
                mCurrentBean?.fragment?.tipsShowType(
                    TipsShowType.ERROR_LIVE_TIPS, appException.errorMsg
                )
                back.invoke()
            }
        }
    }

    /**
     * 跳转到下一个
     */
    private fun currentItemNext(): Boolean {
        val nextPos = mViewpage2.currentItem + 1
        if (mAdapter.getDataByIndex(nextPos) != null) {
            mViewpage2.currentItem = nextPos
            return true
        }
        return false
    }

    /**
     * 切换直播间，切换监听的id和直播id
     */
    private fun initIm(partyImListener: PartyImListener?, mLiveId: Long, userId: Long) {
        if (mPartyImProxy == null) {
            mPartyImProxy = PartyImProxy.create(
                mLiveId,
                userId,
                partyImListener,
                mOwner
            )
        } else {
            mPartyImProxy?.apply {
                this.mLiveId = mLiveId
                mAnchorId = userId
                mPartyImListener = partyImListener
            }
        }
    }

    fun slidingSwitch() {
        mViewpage2.post {
            val position = mViewpage2.currentItem
            val nowData = mAdapter.getDataByIndex(position)
            if (nowData?.fragment?.hashCode() == mCurrentBean?.fragment?.hashCode()) {  //没有切换
                return@post
            }
            //退出上个直播间
            mCurrentBean?.apply {
                roomState = RoomState.PREPARE
                fragment.exitRoom()
            }
            //切换下个直播间
            nowData?.let {
                switchRoom(mCurrentBean, it)
                mCurrentBean = it
                if (position == mAdapter.data.size - 1) {
                    mAutoGetRoomProxy.getNextRoom(it.mAnchorId)
                }
            }
            autoRemovePage()
        }
    }

    /**
     * 延迟工作
     */
    private var mJob: Job? = null

    /**
     * 自动删除上面超过阈值的页面和数据
     */
    private fun autoRemovePage() {
        /**
         * 延时2秒处理
         */
        mJob?.cancel()
        mJob = mViewModel.viewModelScope.launch {
            try {
                delay(DELAYTIME)
                withContext(CoroutineScopeManager.mainDispatcher) {
                    val cPosition = mViewpage2.currentItem
                    if (cPosition > PREORDERQUANTITY) {
                        val count = cPosition - PREORDERQUANTITY
                        if (count > 0 && mAdapter.data.size > count) {
                            mAdapter.data.subList(0, count).clear() // 删除count个元素
                            mAdapter.notifyItemRangeRemoved(0, count)
                        }
                    }
                }
            } finally {
                if (coroutineContext[Job] == mJob) {
                    mJob = null
                }
            }
        }
    }

    fun getCurrentBean(): PartySpectatorBean? {
        return mCurrentBean
    }

    /**
     * 启动房间控制
     *
     * liveInitInfo 外部加入房间数据
     */
    fun startRoomControl(
        mAnchorId: Long,
        @LiveConst.LiveType liveType: Int,
        isMatchCome: Boolean? = null,
        soundStatus: Boolean? = null,
        liveInitInfo: LiveInitInfo? = null,
        roomId: String? = null,
    ) {
        mCurrentBean = initPartySpectatorBean(
            liveType,
            mAnchorId,
            mEditView,
            null,
            mOnSpectatorFragmentListener,
            isMatchCome,
            soundStatus,
            roomId = roomId
        )
        mCurrentBean?.let {
            mAdapter.addFragment(it)
            enterRoom(liveInitInfo = liveInitInfo)
        }
        mAutoGetRoomProxy.getNextRoom(mAnchorId)
    }

    /**
     * 切换到下一个直播间,侧边栏点击进入的
     */
    fun nextData(displayUserBean: DisplayUserBean) {
        if (displayUserBean.base.liveType != null) { //直播类型不能为空
            mViewpage2.setCurrentItem(
                mAdapter.setNextFragment(
                    initPartySpectatorBean(
                        displayUserBean.base.liveType,
                        displayUserBean.base.userId,
                        mEditView,
                        displayUserBean,
                        mOnSpectatorFragmentListener,
                        roomId = displayUserBean.roomId
                    )
                ), false
            )
            slidingSwitch()
        }
    }

    /**
     * 输入房间密码
     */
    private fun partyRoomLockPopup(passwordError: Boolean = false) {
        mCurrentBean?.apply {

            mOnSpectatorFragmentListener.prohibitSliding(mProhibitSliding, false)

            fragment.showPassword(passwordError)
        }
    }

    /**
     * 切换直播间
     */
    private fun switchRoom(upBean: PartySpectatorBean?, nextBean: PartySpectatorBean?) {
        exitRoom(upBean, ExitLiveBean(nextBean))
    }

    /**
     * 切换直播间  切换直播间手动切换
     */
    fun switchRoom(mAnchorId: Long, @LiveConst.LiveType liveType: Int, roomId: String? = null) {
        if (mCurrentBean == null) {
            startRoomControl(mAnchorId, liveType)
            return
        }
        if (mCurrentBean?.mAnchorId != mAnchorId) { //不是一个房间了切换
            mViewpage2.setCurrentItem(
                mAdapter.setNextFragment(
                    initPartySpectatorBean(
                        liveType,
                        mAnchorId,
                        mEditView,
                        null,
                        mOnSpectatorFragmentListener,
                        null,
                        null,
                        roomId
                    )
                ), false
            )
            slidingSwitch()
        } else {
            if (liveType != mCurrentBean?.liveType) { //同一个房间如果直播类型不同，清除直播间重新加载
                mAdapter.data.clear()
                mAdapter.notifyDataSetChanged()
                startRoomControl(mAnchorId, liveType)
            }
        }
    }

    /**
     * 进入直播间
     */
    fun enterRoom(password: String? = null, liveInitInfo: LiveInitInfo? = null) {
        mCurrentBean?.let {
            if (it.roomState == RoomState.PREPARE || it.roomState == RoomState.ERROR) {
                it.fragment.loading()
                it.roomState = RoomState.ENTERREQUEST
                it.password = password
                mViewModel.joinLive(it.mAnchorId, password, liveInitInfo, it.roomId)
            }
        }
    }

    /**
     * 再次进入
     * isAutoPaw 是否自动填充密码
     */
    private fun againEnterRoom(isAutoPaw: Boolean) {
        mCurrentBean?.let {
            if (it.roomState == RoomState.PREPARE || it.roomState == RoomState.ERROR) {
                it.fragment.loading()
                it.roomState = RoomState.ENTERREQUEST
                mViewModel.joinLive(it.mAnchorId, if (isAutoPaw) it.password else null, roomId = it.roomId)
            }
        }
    }

    /**
     * 退出直播间
     * upBean 上一个
     * nextBean 下一个
     */
    private fun exitRoom(upBean: PartySpectatorBean?, exitLiveBean: ExitLiveBean) {
        upBean?.let {
            it.roomState = RoomState.PREPARE
            initIm(null, 0, 0)
            if (exitLiveBean.bean != null && !exitLiveBean.exitAndFinish) {
                it.fragment.loading()
            }
            mViewModel.exitLive(it.mAnchorId, exitLiveBean, it.roomId)
        }
    }

    /**
     * 重连直播间
     */
    private fun recoverJoinLive() {
        mCurrentBean?.let {
            it.roomState = RoomState.ENTERREQUEST
            mViewModel.recoverJoinLive(it.mAnchorId, it.password, roomId = it.roomId)
        }

    }

    /**
     * 网络和长连接变化
     */
    fun network(isNetwork: Boolean, isConnected: Boolean) {
        val lastRoom = SmartFoxManager.getLiveRoom()
        //如果上次是断开连接，这次连接上了，需要重连
        if (lastRoom == null && isConnected) {
            recoverJoinLive()
        }
    }

    /**
     * 界面onResume
     */
    fun onResume() {
        againEnterRoom(true)
    }

    /**
     * 退出当前房间
     */
    fun exitCurrentRoom() {
        LogExt.logI(TAG, "接听电话---退出当前房间")
        mCurrentBean?.fragment?.exitRoom()
        exitRoom(mCurrentBean, ExitLiveBean(null, false))
    }

    /**
     * 界面onPause
     */
    fun onPause() {
    }

    /**
     * 关闭界面
     */
    fun closeActivity() {
        mCurrentBean?.let {
            exitRoom(it, ExitLiveBean(null))
        } ?: mRoomControlListener.exitSuccess()

    }

    /**
     * 销毁
     */
    fun onDestroy() {
        mJob?.cancel()
        mAdapter.onDestroy()
        mCurrentBean = null
    }

    companion object {

        const val TAG = "RoomControlProxy"
        const val PREORDERQUANTITY = 3 //前置数量
        const val DELAYTIME = 3000L //删除等待时间
    }
}